#ifndef MOSES_PRINTVISITOR_H
#define MOSES_PRINTVISITOR_H

#include <ostream>
#include "Ast.h"
#include "MosParser.h"

namespace moses
{
	class PrintVisitor : public Visitor
	{
	public:
	
		PrintVisitor(std::ostream &stream) : m_s(stream) {}
	
		virtual void Accept(BinaryExpr *pItem)
		{
			pItem->GetLeft()->Visit(this);
			
			switch (pItem->GetOP())
			{
				case T_PLUS: m_s << " + "; break;
				case T_MINUS: m_s << " - "; break;
				case T_MUL: m_s << " * "; break;
				case T_DIV: m_s << " / "; break;
				default: m_s << "{UNDEFINED}";
			}
			
			pItem->GetRight()->Visit(this);
		}
		
		virtual void Accept(Call *pItem)
		{
			pItem->GetIdentifier()->Visit(this);

			m_s << "(";
			for (size_t i = 0; i < pItem->GetArguments()->size(); i++)
			{
				(*pItem->GetArguments())[i]->Visit(this);
				if (i+1 < pItem->GetArguments()->size())
					m_s << ", ";
			} 
			m_s << ")";
		}
		
		virtual void Accept(Function *pItem)
		{
			pItem->GetIdentifier()->Visit(this);
			m_s << " :: ";
			
			for (size_t i = 0; i < pItem->GetParameters()->size(); i++)
			{ 
				(*pItem->GetParameters())[i]->Visit(this);
				
				if (i+1 < pItem->GetParameters()->size())
					m_s << ", ";
			}
			m_s << std::endl;
			
			for (size_t i = 0; i < pItem->GetRows()->size(); i++)
			{ 
				(*pItem->GetRows())[i]->Visit(this);				
				m_s << std::endl;
			}
			
			m_s << std::endl;		
		}
		
		virtual void Accept(FunctionRow *pItem)
		{
			m_s << ": ";
			
			pItem->GetIdentifier()->Visit(this);
			
			m_s << " ";
			
			for (size_t i = 0; i < pItem->GetPatternList()->size(); i++)
			{ 
				(*pItem->GetPatternList())[i]->Visit(this);
				
				if (i+1 < pItem->GetPatternList()->size())
					m_s << " ";
			}
			
			m_s << " = ";		
			pItem->GetExpr()->Visit(this);
		}
		
		virtual void Accept(Identifier *pItem)
		{
			m_s << pItem->GetString();
		}
				
		virtual void Accept(Literal *pItem)
		{
			m_s << pItem->GetValue().ToString();
		}
		
		virtual void Accept(Module *pItem)
		{
			pItem->GetFunctions()->VisitAll(this);
		}
				
		virtual void Accept(Pattern *pItem)
		{
			m_s << "x";
		}
				
		virtual void Accept(Type *pItem)
		{
			switch (pItem->GetTypeID())
			{
				case Type::NONE: m_s << "None"; break;
				case Type::BOOL: m_s << "Bool"; break;
				case Type::INT: m_s << "Int"; break;
				case Type::FLOAT: m_s << "Float"; break;
				default: m_s << "{UNDEFINED}"; break;				
			}
		}
		
		virtual void Accept(UnaryExpr *pItem)
		{
			switch (pItem->GetOP())
			{
				case T_MINUS: m_s << " -"; break;
				default: m_s << "{UNDEFINED}"; break;
			}
			pItem->GetExpr()->Visit(this);
		}
		
		std::ostream &m_s;
	};
}

#endif